package com.lagou.monitor.filter;

import com.lagou.monitor.entity.MethodInfoEntity;
import org.apache.dubbo.common.constants.CommonConstants;
import org.apache.dubbo.common.extension.Activate;
import org.apache.dubbo.rpc.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Activate(group = {CommonConstants.CONSUMER})
public class TpnMonitorFilter implements Filter, Runnable {

    private static Map<String, List<MethodInfoEntity>> methodTimes = new ConcurrentHashMap<>();

    private Logger logger = LoggerFactory.getLogger(TpnMonitorFilter.class);

    public TpnMonitorFilter(){
        Executors.newScheduledThreadPool(1).scheduleAtFixedRate(this,5,5, TimeUnit.SECONDS);
    }
    /**
     * 方法执行拦截器：利用拦截器功能在消费端记录每个方法的请求耗时时间
     *
     * @param invoker
     * @param invocation
     * @return
     * @throws RpcException
     */
    @Override
    public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
        //获取执行方法名
        Result result = null;
        try {
            //方法执行开始时间
            Long startTime = System.currentTimeMillis();
            result = invoker.invoke(invocation);
            if (result.getException() instanceof Exception) {
                throw new Exception(result.getException());
            }
            //方法执行结束时间
            Long endTime = System.currentTimeMillis();

            //方法执行耗时
            Long takeTime = endTime - startTime;
            String methodName = invocation.getMethodName();
            List<MethodInfoEntity> methodInfos = methodTimes.get(methodName);

            if(methodInfos == null){
                methodInfos = new ArrayList<>();
                methodTimes.put(methodName,methodInfos);
            }

            //将当前执行方法的记录放入监控集合
            methodInfos.add(new MethodInfoEntity(methodName, endTime, takeTime));
        } catch (Exception e) {
            logger.error("异常：",e);
        }

        return result;
    }

    @Override
    public void run() {
        Date date = new Date();
        SimpleDateFormat sdf = new SimpleDateFormat(",yyyy-MM-dd HH:mm:ss");
        String dateStr = sdf.format(date);
        methodTimes.forEach((k, v)->{
            System.out.println(dateStr + "---->" + k + "的TP90：" + getTp(v, 0.9) + "毫秒；"+ "的TP99：" + getTp(v, 0.99) + "毫秒。");
        });
    }

    private Long getTp(List<MethodInfoEntity> methodInfoEntities , Double rate){
        List<MethodInfoEntity> sortInfo = new ArrayList<>();
        //计算最近一分钟的
        Long startTime = System.currentTimeMillis()-60*1000;
        Long endTime = System.currentTimeMillis();

        //遍历列表集合 取出在一分钟内的请求
        sortInfo = methodInfoEntities.stream().filter(methodInfoEntity ->
                methodInfoEntity.getEndTime().compareTo(startTime)>=0 &&
                        methodInfoEntity.getEndTime().compareTo(endTime)<=0).collect(Collectors.toList());

        //对一分钟内的 根据执行耗时 从小到大排序
        sortInfo.sort((MethodInfoEntity o1, MethodInfoEntity o2) -> o1.getTimes().compareTo(o2.getTimes()));

        //获取当前比例的下标
        int index = (int) (sortInfo.size() * rate);

        return sortInfo.get(index).getTimes();
    }


}
